package jnpf.engine.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.ImmutableList;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jnpf.base.ActionResult;
import jnpf.base.UserInfo;
import jnpf.base.entity.DictionaryDataEntity;
import jnpf.base.entity.SuperExtendEntity;
import jnpf.constant.MsgCode;
import jnpf.engine.entity.*;
import jnpf.engine.enums.FlowStatusEnum;
import jnpf.engine.model.flowbefore.FlowBeforeInfoVO;
import jnpf.engine.model.flowbefore.FlowBeforeListVO;
import jnpf.engine.model.flowengine.FlowModel;
import jnpf.engine.model.flowengine.FlowPagination;
import jnpf.engine.model.flowengine.shuntjson.nodejson.ChildNodeList;
import jnpf.engine.model.flowlaunch.FlowLaunchListVO;
import jnpf.engine.model.flowmonitor.FlowMonitorListVO;
import jnpf.engine.model.flowtask.FlowTaskListModel;
import jnpf.engine.model.flowtask.PaginationFlowTask;
import jnpf.engine.model.flowtemplate.FlowPageListVO;
import jnpf.engine.model.open.*;
import jnpf.engine.model.open.resp.*;
import jnpf.engine.service.*;
import jnpf.exception.WorkFlowException;
import jnpf.permission.entity.UserEntity;
import jnpf.util.JsonUtil;
import jnpf.util.ServiceAllUtil;
import jnpf.util.StringUtil;
import jnpf.util.UserProvider;
import jnpf.util.context.RequestContext;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.HistoryService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskInfo;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;

import static jnpf.consts.AuthConsts.USERDETAIL_USER_ID;
import static jnpf.engine.custom.constants.GlobalProcessVariableConstants.FLOW_TEMPLATE_JSON_ID;

/**
 * 流程引擎对外接口
 *
 * @author denglei
 * @date 2024-11-15
 */
@Slf4j
@Tag(name = "流程引擎对外接口", description = "open")
@RestController
@RequestMapping("/api/workflow/open")
@RequiredArgsConstructor
public class FlowOpenController {

	private final FlowTemplateService flowTemplateService;
	private final FlowTemplateJsonService flowTemplateJsonService;
	private final UserProvider userProvider;
	private final FlowDynamicService flowDynamicService;
	private final FlowTaskNewService flowTaskNewService;
	private final HistoryService historyService;
	private final FlowTaskNodeService flowTaskNodeService;
	private final ServiceAllUtil serviceUtil;
	private final FlowTaskService flowTaskService;
	private final FlowTaskOperatorService flowTaskOperatorService;
	private final TaskService taskService;
	private final FlowOperatorLogService flowOperatorLogService;
	private final FlowableSimulationService processSimulationService;

	/**
	 * 功能描述：流程简单提交
	 * @param flowModel 流动模型
	 * @return {@link ActionResult }
	 * @author denglei
	 * @date 2024-11-15
	 */
	@Operation(summary = "简单提交")
	@PostMapping("/simple")
	public ActionResult submitSimple(@RequestBody FlowModel flowModel) throws WorkFlowException {
		FlowTemplateEntity flowTemplateEntity = flowTemplateService.getOne(Wrappers.lambdaQuery(FlowTemplateEntity.class)
				.eq(FlowTemplateEntity::getEnCode, flowModel.getFlowCode())
				.eq(FlowTemplateEntity::getEnabledMark, 1));
		Assert.notNull(flowTemplateEntity, "流程不存在");
		FlowTemplateJsonEntity flowTemplateJsonEntity = flowTemplateJsonService.getOne(Wrappers.lambdaQuery(FlowTemplateJsonEntity.class)
				.eq(FlowTemplateJsonEntity::getTemplateId, flowTemplateEntity.getId())
				.eq(FlowTemplateJsonEntity::getEnabledMark, 1));
		Assert.notNull(flowTemplateJsonEntity, "流程定义不存在");
		flowModel.setFlowId(flowTemplateJsonEntity.getId());
		flowModel.setStatus(FlowStatusEnum.submit.getMessage());
		log.info("flowModel:{}", JSONObject.toJSONString(flowModel));
		boolean isApp = !RequestContext.isOrignPc();
		UserInfo userInfo = userProvider.get();
		flowModel.setUserInfo(checkUserInfo(userInfo, flowModel.getCreateUserId().toString()));
		flowModel.setSystemId(isApp ? userInfo.getSystemId() : userInfo.getAppSystemId());
		flowDynamicService.batchCreateOrUpdate(flowModel);
		String msg = FlowStatusEnum.save.getMessage().equals(flowModel.getStatus()) ? MsgCode.SU002.get() : MsgCode.SU006.get();
		return ActionResult.success(msg);
	}


	@Operation(summary = "流程模拟")
	@PostMapping("/simulation/{flowCode}")
	public ActionResult<Map<String, Object>> simulation(@PathVariable String flowCode,
	                                                    @RequestBody Map<String, Object> variables) throws WorkFlowException {
		Map<String, Object> stringObjectMap = processSimulationService.simulateProcess(flowCode, variables);
		return ActionResult.success(stringObjectMap);
	}

	@Operation(summary = "获取流程模拟变量")
	@GetMapping("/simulation/variables/{flowCode}")
	public ActionResult<Map<String, Object>> getSimulationVariables(@PathVariable String flowCode) throws WorkFlowException {
		Map<String, Object> stringObjectMap = processSimulationService.simulateVariables(flowCode);
		return ActionResult.success(stringObjectMap);
	}

	@Operation(summary = "获取流程图json")
	@GetMapping("/flowTemplate/{flowCode}")
	public ActionResult<String> getFlowTemplateJson(@PathVariable String flowCode) throws WorkFlowException {
		return ActionResult.success(processSimulationService.getFlowTemplateJson(flowCode));
	}

	/**
	 * 功能描述：发起撤回
	 * @param flowRevokeReq 流撤销请求
	 * @return {@link ActionResult }
	 * @author denglei
	 * @date 2024-11-15
	 */
	@Operation(summary = "发起撤回")
	@PostMapping("/revoke")
	public ActionResult revoke(@RequestBody FlowRevokeReq flowRevokeReq) throws WorkFlowException {
		UserInfo userInfo = userProvider.get();
		FlowModel flowModel = new FlowModel();
		flowModel.setUserInfo(userInfo);
		flowModel.setPointFlag(true);
		flowModel.setHandleOpinion(flowRevokeReq.getReason());
		HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
				.processInstanceId(flowRevokeReq.getFlowInstanceId()).singleResult();
		flowTaskNewService.revoke(ImmutableList.of(historicProcessInstance.getBusinessKey()), flowModel, true);
		return ActionResult.success("撤回成功");
	}


	/**
	 * 功能描述：流程终止
	 * @param flowCancelReq 流终止请求
	 * @return {@link ActionResult }
	 * @author denglei
	 * @date 2024-11-15
	 */
	@Operation(summary = "流程终止")
	@PostMapping("/cancel")
	public ActionResult cancelFlow(@RequestBody FlowCancelReq flowCancelReq) throws WorkFlowException {
		UserInfo userInfo = userProvider.get();
		FlowModel flowModel = new FlowModel();
		flowModel.setUserInfo(userInfo);
		flowModel.setPointFlag(true);
		flowModel.setHandleOpinion(flowCancelReq.getReason());
		flowModel.setUserInfo(flowModel.getUserInfo());
		flowTaskNewService.cancel(Collections.singletonList(flowCancelReq.getFlowInstanceId()), flowModel);
		return ActionResult.success("终止成功");
	}


	/**
	 * 功能描述：删除流程
	 * @param flowDeleteReq
	 * @return {@link ActionResult }
	 * @author duanxu
	 * @date 2025-1-13
	 */
	@Operation(summary = "流程删除")
	@PostMapping("/delete")
	public ActionResult deleteFlow(@RequestBody FlowDeleteReq flowDeleteReq) throws WorkFlowException {
		List<String> taskIdList = taskService.createTaskQuery()
					.processInstanceIdIn(flowDeleteReq.getInstanceIds())
					.active()
					.list()
					.stream()
					.map(TaskInfo::getId)
					.collect(Collectors.toList());
		String[] ids = new String[taskIdList.size()];
		ids = taskIdList.toArray(ids);
		flowTaskService.delete(ids);
		return ActionResult.success("删除成功");
	}

	@Operation(summary = "流程审核")
	@PostMapping("/audit")
	public ActionResult auditFlow(@RequestBody @Validated FlowAuditReq flowAuditReq) throws WorkFlowException {
		String taskId = flowAuditReq.getId();
		// 创建任务查询
		if(flowAuditReq.isResubmit()){
			// 查询流程实例di
			String processInstanceId = flowAuditReq.getProcessInstanceId();
			// 通过流程实例id查询所有任务
			List<Task> list = taskService.createTaskQuery()
					.processInstanceId(processInstanceId) // 根据流程实例ID过滤任务
					.active() // 只查询激活状态的任务
					.orderByTaskCreateTime().desc() // 按任务创建时间倒序排序
					.list();
			Task task = list.get(list.size() - 1);
			if (ObjectUtil.isNull(task)) {
				throw new WorkFlowException("发起节点不存在");
			}
			taskId = task.getId();
			if (StringUtil.isEmpty(flowAuditReq.getFlowId())) {
				String flowId = flowTemplateService.getOne(Wrappers.lambdaQuery(FlowTemplateEntity.class)
								.eq(FlowTemplateEntity::getEnCode, flowAuditReq.getFlowCode())
								.eq(SuperExtendEntity.SuperExtendDEEntity::getEnabledMark, 1))
						.getId();
				flowAuditReq.setFlowId(flowId);
			}
		}
		if(StringUtil.isEmpty(taskId)){
			throw new WorkFlowException("任务id不能为空");
		}
		LambdaQueryWrapper<FlowTaskOperatorEntity> operatorEntityLambdaQueryWrapper = new LambdaQueryWrapper<>();
		//原本通过taskNodeId 也就是任务id可以唯一定位 此条数据, 因为有委派业务,所以1个任务id可能有多个
		operatorEntityLambdaQueryWrapper.eq(FlowTaskOperatorEntity::getTaskNodeId,taskId);
		UserInfo userInfo = userProvider.get();
		operatorEntityLambdaQueryWrapper.eq(FlowTaskOperatorEntity::getHandleId,userInfo.getUserId());
		FlowTaskOperatorEntity operator = flowTaskOperatorService.getOne(operatorEntityLambdaQueryWrapper);
		//字段转换
		flowAuditReq.setUserInfo(userInfo);
		flowTaskNewService.auditAll(new FlowTaskEntity(), operator, flowAuditReq);
		return ActionResult.success("审核成功");
	}

	/**
	 * 功能描述：查询代办流程分页
	 * @param flowQueryWaitReq 代办查询入参
	 * @return {@link ActionResult }
	 * @author duanxu
	 */
	@Operation(summary = "代办列表-分页")
	@GetMapping("/waitList")
	public ActionResult<FlowQueryWaitResp> waitList(FlowQueryWaitReq flowQueryWaitReq) throws WorkFlowException {
		PaginationFlowTask paginationFlowTask = generatorQueryParam(flowQueryWaitReq);
		List<FlowTaskListModel> data = flowTaskService.getWaitList(paginationFlowTask);
		FlowQueryWaitResp result = new FlowQueryWaitResp();
		result.setData(processFlowQuery(data, false, flowQueryWaitReq));
		result.setPage(paginationFlowTask);
		return ActionResult.success(result);
	}

	/**
	 * 功能描述：查询已办流程分页
	 * @param flowQueryDoneReq 已办查询入参
	 * @return {@link ActionResult }
	 * @author duanxu
	 */
	@Operation(summary = "已办列表-分页")
	@GetMapping("/doneList")
	public ActionResult<FlowQueryDoneResp> doneList(FlowQueryDoneReq flowQueryDoneReq) throws WorkFlowException {
		PaginationFlowTask paginationFlowTask = generatorQueryParam(flowQueryDoneReq);
		List<FlowTaskListModel> data = flowTaskService.getTrialList(paginationFlowTask);
		FlowQueryDoneResp result = new FlowQueryDoneResp();
		result.setData(processFlowQuery(data, false, flowQueryDoneReq));
		result.setPage(paginationFlowTask);
		return ActionResult.success(result);
	}

	/**
	 * 功能描述：查询抄送事宜流程分页
	 * @param flowQueryCopyTaskReq 抄送事宜查询入参
	 * @return {@link ActionResult }
	 * @author duanxu
	 */
	@Operation(summary = "抄送事宜列表-分页")
	@GetMapping("/copyTaskList")
	public ActionResult<FlowQueryCopyTaskResp> copyTaskList(FlowQueryCopyTaskReq flowQueryCopyTaskReq) throws WorkFlowException {
		PaginationFlowTask paginationFlowTask = generatorQueryParam(flowQueryCopyTaskReq);
		List<FlowTaskListModel> data = flowTaskService.getCirculateList(paginationFlowTask);
		FlowQueryCopyTaskResp result = new FlowQueryCopyTaskResp();
		result.setData(processFlowQuery(data, false, flowQueryCopyTaskReq));
		result.setPage(paginationFlowTask);
		return ActionResult.success(result);
	}


	/**
	 * 功能描述：查询我发起的流程分页
	 * @param flowQueryLaunchReq 我发起的查询入参
	 * @return {@link ActionResult }
	 * @author duanxu
	 */
	@Operation(summary = "我发起的列表-分页")
	@GetMapping("/launchList")
	public ActionResult<FlowQueryLaunchResp> launchList(FlowQueryLaunchReq flowQueryLaunchReq) throws WorkFlowException {
		PaginationFlowTask paginationFlowTask = generatorQueryParam(flowQueryLaunchReq);
		List<FlowTaskEntity> data = flowTaskService.getLaunchList(paginationFlowTask);
		List<FlowLaunchListVO> listVO = JsonUtil.getJsonToList(data, FlowLaunchListVO.class);
		FlowQueryLaunchResp result = new FlowQueryLaunchResp();
		result.setData(listVO);
		result.setPage(paginationFlowTask);
		return ActionResult.success(result);
	}


	/**
	 * 功能描述：查询我发起且完结的流程分页
	 * @param flowQueryMonitorReq 我发起且完结的查询入参
	 * @return {@link ActionResult }
	 * @author duanxu
	 */
	@Operation(summary = "我发起且完结的列表-分页")
	@GetMapping("/monitorList")
	public ActionResult<FlowQueryMonitorResp> monitorList(FlowQueryMonitorReq flowQueryMonitorReq) throws WorkFlowException {
		PaginationFlowTask paginationFlowTask = generatorQueryParam(flowQueryMonitorReq);
		paginationFlowTask.setPageOpType("flowMyDone");
		List<FlowTaskEntity> data = flowTaskService.getMonitorList(paginationFlowTask);
		List<UserEntity> userList = serviceUtil.getUserName(data.stream().map(t -> t.getCreatorUserId()).collect(Collectors.toList()));
		List<FlowMonitorListVO> listVO = new LinkedList<>();
		for (FlowTaskEntity taskEntity : data) {
			//用户名称赋值
			FlowMonitorListVO vo = JsonUtil.getJsonToBean(taskEntity, FlowMonitorListVO.class);
			UserEntity user = userList.stream().filter(t -> t.getId().equals(taskEntity.getCreatorUserId())).findFirst().orElse(null);
			vo.setUserName(user != null ? user.getRealName() + "/" + user.getAccount() : "");
			listVO.add(vo);
		}
		FlowQueryMonitorResp result = new FlowQueryMonitorResp();
		result.setData(listVO);
		result.setPage(paginationFlowTask);
		return ActionResult.success(result);
	}

	/**
	 * 功能描述：流程信息
	 * @param processInstanceId 流程实例id
	 * @return {@link ActionResult }
	 * @author duanxu
	 */
	@Operation(summary = "流程信息")
	@GetMapping("/flowInfo/{processInstanceId}")
	public ActionResult<FlowBeforeInfoVO> flowInfo(@PathVariable String processInstanceId) throws WorkFlowException {
		//查询流程实例历史流程节点
		HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
		String flowId = (String)historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).variableName(FLOW_TEMPLATE_JSON_ID).singleResult().getValue();
		//封装查询参数
		FlowModel flowModel = new FlowModel();
		flowModel.setId(processInstance.getId());
		flowModel.setTaskOperatorId(processInstance.getId());
		flowModel.setFlowId(flowId);
		FlowBeforeInfoVO vo = flowTaskNewService.getBeforeInfo(flowModel);
		//处理当前默认值
		if (vo != null && vo.getFlowFormInfo() != null && StringUtil.isNotEmpty(vo.getFlowFormInfo().getPropertyJson()) && vo.getFlowFormInfo().getFormType() == 2) {
			UserInfo userInfo = userProvider.get();
			Map<String, Integer> havaDefaultCurrentValue = new HashMap<>();
			vo.getFlowFormInfo().setPropertyJson(FlowBeforeController.setDefaultCurrentValue(vo.getFlowFormInfo().getPropertyJson(), havaDefaultCurrentValue, userInfo));
		}
		return ActionResult.success(vo);
	}

	/**
	 * 功能描述：查询流程设计列表
	 *
	 * @param flowPagination 查询参数
	 * @return {@link ActionResult }
	 * @author duanxu
	 */
	@Operation(summary = "流程模板列表")
	@GetMapping("/template/list")
	public ActionResult<List<FlowPageListVO>> templateList(FlowPagination flowPagination) throws WorkFlowException {
		flowPagination.setCurrentPage(1L);
		flowPagination.setPageSize(Integer.MAX_VALUE);
		// 固定返回发起流程
		flowPagination.setFlowType(0);
		List<FlowTemplateEntity> list = flowTemplateService.getListAll(flowPagination, true);
		List<DictionaryDataEntity> dictionList = serviceUtil.getDictionName(list.stream().map(FlowTemplateEntity::getCategory).collect(Collectors.toList()));
		List<UserEntity> userList = serviceUtil.getUserName(list.stream().map(FlowTemplateEntity::getCreatorUserId).collect(Collectors.toList()));
		List<FlowPageListVO> listVO = new ArrayList<>();
		for (FlowTemplateEntity entity : list) {
			FlowPageListVO vo = JsonUtil.getJsonToBean(entity, FlowPageListVO.class);
			DictionaryDataEntity dataEntity = dictionList.stream().filter(t -> t.getId().equals(entity.getCategory())).findFirst().orElse(null);
			vo.setCategory(dataEntity != null ? dataEntity.getFullName() : "");
			UserEntity userEntity = userList.stream().filter(t -> t.getId().equals(entity.getCreatorUserId())).findFirst().orElse(null);
			vo.setCreatorUser(userEntity != null ? userEntity.getRealName() + "/" + userEntity.getAccount() : "");
			listVO.add(vo);
		}
		return ActionResult.success(listVO);
	}


	/**
	 * 保存操作日志
	 * @param flowOperatorLogReq
	 * @return
	 * @throws WorkFlowException
	 */
	@PostMapping("/log")
	public ActionResult log(@RequestBody FlowOperatorLogReq flowOperatorLogReq) throws WorkFlowException {
		flowOperatorLogService.log(flowOperatorLogReq);
		return ActionResult.success("操作成功");
	}


	private PaginationFlowTask generatorQueryParam(FlowQueryReq flowQueryReq){
		PaginationFlowTask paginationFlowTask = new PaginationFlowTask();
		BeanUtil.copyProperties(flowQueryReq, paginationFlowTask);
		if (StringUtil.isNotEmpty(flowQueryReq.getStartTime())) {
			paginationFlowTask.setStartTime(DateUtil.parseDateTime(flowQueryReq.getStartTime()).getTime());
		}
		if (StringUtil.isNotEmpty(flowQueryReq.getEndTime())){
			paginationFlowTask.setEndTime(DateUtil.parseDateTime(flowQueryReq.getEndTime()).getTime());
		}
		if (StringUtil.isNotEmpty(flowQueryReq.getKeyWord())) {
			paginationFlowTask.setKeyword(flowQueryReq.getKeyWord());
		}
		paginationFlowTask.setCurrentPage(flowQueryReq.getCurrent());
		paginationFlowTask.setPageSize(flowQueryReq.getSize());
		paginationFlowTask.setSort("Desc");
		return paginationFlowTask;
	}

	/**
	 * 分页返回数据封装
	 * @param data 查询结果
	 * @param isBatch 是否为批量审批
	 * @param flowQueryReq 查询入参
	 * @return
	 */
	private List<FlowBeforeListVO> processFlowQuery(List<FlowTaskListModel> data, boolean isBatch, FlowQueryReq flowQueryReq){
		List<FlowBeforeListVO> listVO = new LinkedList<>();
		List<UserEntity> userList = serviceUtil.getUserName(data.stream().map(FlowTaskListModel::getCreatorUserId).collect(Collectors.toList()));
		List<FlowTaskNodeEntity> taskNodeList = new ArrayList<>();
		List<String> taskNodeIdList = data.stream().map(FlowTaskListModel::getThisStepId).collect(Collectors.toList());
		if (isBatch) {
			taskNodeList.addAll(flowTaskNodeService.getList(taskNodeIdList, FlowTaskNodeEntity::getId, FlowTaskNodeEntity::getNodePropertyJson));
		}
		for (FlowTaskListModel task : data) {
			FlowBeforeListVO vo = JsonUtil.getJsonToBean(task, FlowBeforeListVO.class);
			//用户名称赋值
			UserEntity user = userList.stream().filter(t -> t.getId().equals(vo.getCreatorUserId())).findFirst().orElse(null);
			vo.setUserName(user != null ? user.getRealName() + "/" + user.getAccount() : "");
			FlowTaskNodeEntity taskNode = taskNodeList.stream().filter(t -> t.getId().equals(task.getThisStepId())).findFirst().orElse(null);
			if (isBatch && taskNode != null) {
				ChildNodeList childNode = JsonUtil.getJsonToBean(taskNode.getNodePropertyJson(), ChildNodeList.class);
				vo.setApproversProperties(JsonUtil.getObjectToString(childNode.getProperties()));
			}
			vo.setFlowVersion(StringUtil.isEmpty(vo.getFlowVersion()) ? "" : vo.getFlowVersion());
			listVO.add(vo);
		}

		return listVO;
	}


	private UserInfo checkUserInfo(UserInfo userInfo, String userId) {
		if (StringUtil.isEmpty(userId)) {
			return userInfo;
		}
		if (!userInfo.getUserId().equals(userId)) {
			UserInfo newUserInfo = new UserInfo();
			newUserInfo.setUserId(userId);
			newUserInfo.setGrantType("password");
			newUserInfo.setUserDetailKey(USERDETAIL_USER_ID);
			return newUserInfo;
		}
		return userInfo;
	}

}
